package bma.common.httpclient;

import java.io.IOException;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;

import bma.common.langutil.core.DateTimeUtil;
import bma.common.langutil.core.ExceptionUtil;
import bma.common.langutil.core.Function;

public class CommonHttpClient implements HttpClientFactory {

	private final org.slf4j.Logger log = org.slf4j.LoggerFactory
			.getLogger(HttpClientUtil.class);

	private static CommonHttpClient instance = new CommonHttpClient();

	public CommonHttpClient() {
		super();
	}

	public static CommonHttpClient getInstance() {
		return instance;
	}

	@Override
	public DefaultHttpClient createClient(HttpParams params) {
		return new DefaultHttpClient(params);
	}

	private static String max(String s, int len) {
		if (s == null)
			return "";
		if (s.length() < len)
			return s;
		return s.substring(0, len);
	}

	public static String getContent(String url, List<NameValuePair> params,
			int timeout, boolean getMethod) throws ClientProtocolException,
			IOException {
		return getContent(url, params, timeout, getMethod, null);
	}

	public static String getContent(String url, List<NameValuePair> params,
			int timeout, boolean getMethod, Function<HttpRequest, Boolean> fun)
			throws ClientProtocolException, IOException {
		String pstr = "";
		StringEntity post = null;
		if (params != null && !params.isEmpty()) {
			pstr = URLEncodedUtils.format(params, "UTF-8");
		}
		if (getMethod) {
			url = HttpClientUtil.appendUrlParam(url, pstr);
		} else {
			post = new StringEntity(pstr, "UTF-8");
		}

		HttpUriRequest req = null;
		if (getMethod) {
			req = new HttpGet(url);
		} else {
			HttpPost preq = new HttpPost(url);
			preq.addHeader("Content-Type", "application/x-www-form-urlencoded");
			preq.setEntity(post);
			req = preq;
		}
		if (fun != null) {
			if (!fun.apply(req)) {
				throw new IllegalArgumentException("request apply fail");
			}
		}

		HttpParams hparams = new BasicHttpParams();
		HttpConnectionParams.setConnectionTimeout(hparams, timeout);
		HttpConnectionParams.setSoTimeout(hparams, timeout);

		DefaultHttpClient client = getInstance().createClient(hparams);
		HttpResponse resp = null;
		long start = System.currentTimeMillis();
		try {
			resp = client.execute(req);
			HttpEntity entity = resp.getStatusLine().getStatusCode() == 200 ? resp
					.getEntity() : null;
			if (entity != null) {
				long len = entity.getContentLength();
				String r = EntityUtils.toString(entity);
				if (instance.log.isDebugEnabled()) {
					instance.log
							.debug("getContent({},{},{}) - ({},{},{}) : {}",
									new Object[] {
											url,
											getMethod ? null : max(pstr, 256),
											DateTimeUtil.formatPeriod(timeout),
											DateTimeUtil.formatPeriod(System
													.currentTimeMillis()
													- start),
											resp == null ? "<null>" : resp
													.getStatusLine(),
											len == -1 ? r.length() : len,
											max(r, 128) });
				}
				return r;
			} else {
				if (instance.log.isDebugEnabled()) {
					instance.log.debug(
							"getContent({},{},{}) - ({},{},0) : {}",
							new Object[] {
									url,
									getMethod ? null : max(pstr, 256),
									DateTimeUtil.formatPeriod(timeout),
									DateTimeUtil.formatPeriod(System
											.currentTimeMillis() - start),
									resp.getStatusLine(), "<null>" });
				}
				return "";
			}
		} catch (Exception e) {
			if (instance.log.isDebugEnabled()) {
				instance.log.debug(
						"getContent({},{},{}) - ({},{},{}) : fail",
						new Object[] {
								url,
								getMethod ? null : max(pstr, 256),
								DateTimeUtil.formatPeriod(timeout),
								DateTimeUtil.formatPeriod(System
										.currentTimeMillis() - start),
								resp == null ? "<null>" : resp.getStatusLine(),
								e });
			}
			if (e instanceof ClientProtocolException) {
				throw (ClientProtocolException) e;
			}
			if (e instanceof IOException) {
				throw (IOException) e;
			}
			throw ExceptionUtil.throwRuntime(e);
		}
	}
}
